package com.qiaofang.applet.service.property.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.mongodb.client.result.UpdateResult;
import com.qiaofang.applet.common.base.MongoBaseService;
import com.qiaofang.applet.common.context.QfContext;
import com.qiaofang.applet.common.context.QfContextHolder;
import com.qiaofang.applet.common.util.RedisKeyUtil;
import com.qiaofang.applet.common.util.RedisUtil;
import com.qiaofang.applet.constants.*;
import com.qiaofang.applet.service.member.domain.EmployeeProperty;
import com.qiaofang.applet.service.member.repository.EmployeePropertyRepository;
import com.qiaofang.applet.service.other.domain.CityCompany;
import com.qiaofang.applet.service.other.domain.PropertyRules;
import com.qiaofang.applet.service.other.domain.PropertyWaterMark;
import com.qiaofang.applet.service.other.repository.CityCompanyRepository;
import com.qiaofang.applet.service.other.service.dto.EstateListAggregationDto;
import com.qiaofang.applet.service.other.service.dto.MainSearchDetailDTO;
import com.qiaofang.applet.service.other.service.dto.MainSearchQueryDTO;
import com.qiaofang.applet.service.property.domain.EstateHouseTypeFy;
import com.qiaofang.applet.service.property.domain.FirsthandEstate;
import com.qiaofang.applet.service.property.domain.Property;
import com.qiaofang.applet.service.property.repository.EstateHouseTypeFyRepository;
import com.qiaofang.applet.service.property.repository.PropertyRepository;
import com.qiaofang.applet.service.property.service.CommonService;
import com.qiaofang.applet.service.property.service.FirsthandEstateService;
import com.qiaofang.applet.service.property.service.PropertyService;
import com.qiaofang.applet.service.property.service.QueryCommonService;
import com.qiaofang.applet.service.property.service.dto.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

import static org.springframework.data.domain.Sort.Direction.DESC;

/**
 * @author QF2019
 */
@Slf4j
@Service
public class PropertyServiceImpl extends MongoBaseService<Property, String> implements PropertyService, QueryCommonService {

    private final PropertyRepository propertyRepository;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private EstateHouseTypeFyRepository estateHouseTypeFyRepository;

    @Autowired
    private EmployeePropertyRepository employeePropertyRepository;

    @Autowired
    private FirsthandEstateService firsthandEstateService;

    @Autowired
    private CityCompanyRepository cityCompanyRepository;

    @Autowired
    private CommonService commonService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    public PropertyServiceImpl(PropertyRepository repository) {
        super(repository);
        this.propertyRepository = repository;
    }

    @Override
    public Property findByPropertyUuidAndCompanyUuid(String propertyUuid, String companyUuid) {
        return propertyRepository.findByPropertyUuidAndCompanyUuid(propertyUuid, companyUuid);
    }

    @Override
    public Property findByPropertyUniqueUuid(String propertyUniqueUuid) {
        return propertyRepository.findFirstByPropertyUniqueUuid(propertyUniqueUuid);
    }

    private void creatPropertyFields(Query query) {
        query.fields().include("propertyUniqueUuid")
                .include("propertyUuid")
                .include("cityCode")
                .include("propertyNo")
                .include("districtName")
                .include("areaName")
                .include("estateName")
                .include("title")
                .include("mainImageUrl")
                .include("houseType")
                .include("square")
                .include("direction")
                .include("completeYear")
                .include("existVr")
                .include("countF")
                .include("countT")
                .include("countW")
                .include("estateUniqueUuid")
                .include("recommend")
                .include("upDownFlag")
                .include("deptName1")
                .include("employeeUuid1Name")
                .include("tradeType")
                .include("createdTime")
                .include("propertyExplainList");
    }

    private void createSaleFields(Query query) {
        creatPropertyFields(query);
        query.fields().include("sellPrice")
                .include("sellUnitPrice")
                .include("recommendSort");
    }

    private void createRentFields(Query query) {
        creatPropertyFields(query);
        query.fields().include("rentPrice")
                .include("rentUnitPrice")
                .include("recommendSort");
    }


    private Criteria createFindQuery(PropertyQueryDto queryDto) {
        QfContext qfContext = QfContextHolder.getContext();

        Criteria criteria = Criteria.where("corporationCode").is(StringUtils.defaultString(queryDto.getCorporationCode(), qfContext.getCorporationCode()));

        if (StringUtils.isNotBlank(queryDto.getUpDownFlag())) {
            criteria.and("upDownFlag").is(queryDto.getUpDownFlag());
        }
        if (StringUtils.isNotBlank(queryDto.getCityCode())) {
            criteria.and("cityCode").is(queryDto.getCityCode());
        } else if (!CollectionUtils.isEmpty(queryDto.getCityCodes())){
            criteria.and("cityCode").in(queryDto.getCityCodes());
        }
        if (StringUtils.isNotBlank(queryDto.getAreaUuid())) {
            criteria.and("areaUuid").is(queryDto.getAreaUuid());
        }
        if (StringUtils.isNotBlank(queryDto.getAreaName())) {
            criteria.and("areaName").is(queryDto.getAreaName());
        }
        if (StringUtils.isNotBlank(queryDto.getDistrictUuid())) {
            criteria.and("districtUuid").is(queryDto.getDistrictUuid());
        }
        if (StringUtils.isNotBlank(queryDto.getDistrictName())) {
            criteria.and("districtName").is(queryDto.getDistrictName());
        }
        if (StringUtils.isNotBlank(queryDto.getEstateUuid())) {
            criteria.and("estateUuid").is(queryDto.getEstateUuid());
        }
        if (StringUtils.isNotBlank(queryDto.getEstateUniqueUuid())) {
            criteria.and("estateUniqueUuid").is(queryDto.getEstateUniqueUuid());
        }
        if (StringUtils.isNotBlank(queryDto.getEstateName())) {
            criteria.and("estateName").regex(queryDto.getEstateName());
        }
        if (queryDto.getCountF() != null) {
            criteria.and("countF").is(queryDto.getCountF());
        }
        if (queryDto.getRecommend() != null) {
            criteria.and("recommend").is(queryDto.getRecommend());
        }
        if (!CollectionUtils.isEmpty(queryDto.getPropertyUuids())) {
            criteria.and("propertyUuid").in(queryDto.getPropertyUuids());
        }
        if (!CollectionUtils.isEmpty(queryDto.getPropertyUniqueUuids())) {
            criteria.and("propertyUniqueUuid").in(queryDto.getPropertyUniqueUuids());
        }
        if (!CollectionUtils.isEmpty(queryDto.getNotPropertyUniqueUuids())) {
            criteria.and("propertyUniqueUuid").nin(queryDto.getNotPropertyUniqueUuids());
        }
        if (StringUtils.isNotBlank(queryDto.getDirection())) {
            criteria.and("direction").is(queryDto.getDirection());
        }
        if (StringUtils.isNotBlank(queryDto.getDecoration())) {
            criteria.and("decoration").is(queryDto.getDecoration());
        }
        if (StringUtils.isNotBlank(queryDto.getFloorRange())) {
            criteria.and("floorRange").is(queryDto.getFloorRange());
        }
        if (queryDto.getElevator() != null) {
            criteria.and("elevator").is(queryDto.getElevator());
        }
        if (queryDto.getExistVr() != null) {
            criteria.and("existVr").is(queryDto.getExistVr());
        }
        if (queryDto.getMinSquare() != null && queryDto.getMaxSquare() != null) {
            criteria.andOperator(
                    Criteria.where("square").gte(queryDto.getMinSquare()),
                    Criteria.where("square").lte(queryDto.getMaxSquare())
            );
        } else if (queryDto.getMinSquare() != null) {
            criteria.andOperator(
                    Criteria.where("square").gte(queryDto.getMinSquare()),
                    Criteria.where("square").lte(new BigDecimal(999999999))
            );
        } else if (queryDto.getMaxSquare() != null) {
            criteria.andOperator(
                    Criteria.where("square").gte(0),
                    Criteria.where("square").lte(queryDto.getMaxSquare())
            );
        }
        criteria.and("square").ne(null);

        if (StringUtils.isNotEmpty(queryDto.getFuzzyQueryStr())) {
            criteria.orOperator(Criteria.where("propertyNo").regex(".*?" + queryDto.getFuzzyQueryStr() + ".*"),
                    Criteria.where("estateName").regex(".*?" + queryDto.getFuzzyQueryStr() + ".*"),
                    Criteria.where("employeeUuid1Name").regex(".*?" + queryDto.getFuzzyQueryStr() + ".*"));
        }
        if (queryDto.isValidStatus()) {
            criteria.and("tradeStatus").is("有效");
        }
        if (Objects.nonNull(queryDto.getEstateRockId())) {
            criteria.and("estateRockId").is(queryDto.getEstateRockId());
        }

        if (!CollectionUtils.isEmpty(queryDto.getTradeStatusSet())) {
            criteria.and("tradeStatus").in(queryDto.getTradeStatusSet());
        }

        if (queryDto.getNewStatus() != null && queryDto.getNewStatus()) {
            criteria.and("createdTime").gte(new Timestamp(System.currentTimeMillis() - (7 * DateUtil.DAY_MILLISECONDS)));
        }

        return criteria;
    }

    private Criteria createSaleQuery(SalePropertyQueryDto queryDto) {
        Criteria c = new Criteria();

        c.orOperator(Criteria.where("tradeType").is(PropertyTradeTypeConstants.SALE), Criteria.where("tradeType").is(PropertyTradeTypeConstants.ALL));

        if (queryDto.getMinSellPrice() != null && queryDto.getMaxSellPrice() != null) {
            c.andOperator(
                    Criteria.where("sellPrice").gte(queryDto.getMinSellPrice()),
                    Criteria.where("sellPrice").lte(queryDto.getMaxSellPrice())
            );
        } else if (queryDto.getMinSellPrice() != null) {
            c.andOperator(
                    Criteria.where("sellPrice").gte(queryDto.getMinSellPrice()),
                    Criteria.where("sellPrice").lte(new BigDecimal(999999999))
            );
        } else if (queryDto.getMaxSellPrice() != null) {
            c.andOperator(
                    Criteria.where("sellPrice").gte(0),
                    Criteria.where("sellPrice").lte(queryDto.getMaxSellPrice())
            );
        }
        c.and("sellPrice").ne(null);
        c.and("sellUnitPrice").ne(null);
        return c;
    }

    private Criteria createRentQuery(RentPropertyQueryDto queryDto) {
        Criteria c = new Criteria();

        c.orOperator(Criteria.where("tradeType").is(PropertyTradeTypeConstants.RENT), Criteria.where("tradeType").is(PropertyTradeTypeConstants.ALL));

        if (queryDto.getMinRentPrice() != null && queryDto.getMaxRentPrice() != null) {
            c.andOperator(
                    Criteria.where("rentPrice").gte(queryDto.getMinRentPrice()),
                    Criteria.where("rentPrice").lte(queryDto.getMaxRentPrice())
            );
        } else if (queryDto.getMinRentPrice() != null) {
            c.andOperator(
                    Criteria.where("rentPrice").gte(queryDto.getMinRentPrice()),
                    Criteria.where("rentPrice").lte(new BigDecimal(999999999))
            );
        } else if (queryDto.getMaxRentPrice() != null) {
            c.andOperator(
                    Criteria.where("rentPrice").gte(new BigDecimal(0)),
                    Criteria.where("rentPrice").lte(queryDto.getMaxRentPrice())
            );
        }
        c.and("rentPrice").ne(null);
//        c.and("rentUnitPrice").ne(null);
        return c;
    }

    private void handleQueryDto(PropertyQueryDto queryDto) {
        if (StringUtils.isNotEmpty(queryDto.getEstateUniqueUuid()) && StringUtils.isNotEmpty(queryDto.getPhotoUuid())) {
            //如果同时存在楼盘唯一uuid和户型图片uuid，即为户型图跳转查询场景
            List<String> propertyUniqueUuids = Optional.ofNullable(estateHouseTypeFyRepository.findByEstateUniqueUuidAndPhotoUuid(queryDto.getEstateUniqueUuid(), queryDto.getPhotoUuid())).orElseGet(Lists::newArrayList)
                    .stream().map(EstateHouseTypeFy::getPropertyUniqueUuid).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(propertyUniqueUuids)) {
                propertyUniqueUuids = new LinkedList<>();
                propertyUniqueUuids.add("");
            }
            queryDto.setPropertyUniqueUuids(propertyUniqueUuids);
            queryDto.setCityCode(null);
        }
    }

    @Override
    public Page<Property> findAllSaleByParams(SalePropertyQueryDto queryDto, Pageable pageable) {

        handleQueryDto(queryDto);

        Long startTime = System.currentTimeMillis();

        // 1、拼查询公共条件
        Criteria commonCriteria = createFindQuery(queryDto);

        // 2、拼每个查询特有的一些查询条件
        Criteria saleCritera = createSaleQuery(queryDto);
        Query queryCriteria = new Query();
        queryCriteria.addCriteria(new Criteria().andOperator(commonCriteria, saleCritera));

        // 3、拼分页参数
        queryCriteria.with(pageable);

        // 4、拼排序参数
        createFindSort(queryCriteria, queryDto.getSort());

        // 5、指定字段
        createSaleFields(queryCriteria);
        log.info("处理条件总时间为: " + (System.currentTimeMillis() - startTime));

        // 6、查询记录条件
        long count = mongoTemplate.count(queryCriteria, Property.class);
        log.info("count总时间为: " + (System.currentTimeMillis() - startTime));

        List<Property> result = new ArrayList<>();
        if (count > 0) {
            // 7、分页查询数据
            result = mongoTemplate.find(queryCriteria, Property.class);
            log.info("query总时间为: " + (System.currentTimeMillis() - startTime));
        }
        return PageableExecutionUtils.getPage(result, pageable, () -> count);
    }

    @Override
    public Page<Property> findSameSaleByParams(String propertyUniqueUuid, SalePropertyQueryDto queryDto, Pageable pageable) {
        handleQueryDto(queryDto);

        Long startTime = System.currentTimeMillis();

        // 1、拼查询公共条件
        Criteria commonCriteria = createFindQuery(queryDto);

        // 2、拼每个查询特有的一些查询条件
        Criteria saleCritera = createSaleQuery(queryDto);

        //过滤自身
        saleCritera.and("propertyUniqueUuid").ne(propertyUniqueUuid);

        Query queryCriteria = new Query();
        queryCriteria.addCriteria(new Criteria().andOperator(commonCriteria, saleCritera));

        // 3、拼分页参数
        queryCriteria.with(pageable);

        // 4、拼排序参数
        createFindSort(queryCriteria, queryDto.getSort());

        // 5、指定字段
        createSaleFields(queryCriteria);
        log.info("处理条件总时间为: " + (System.currentTimeMillis() - startTime));

        // 6、查询记录条件
        long count = mongoTemplate.count(queryCriteria, Property.class);
        log.info("count总时间为: " + (System.currentTimeMillis() - startTime));

        List<Property> result = new ArrayList<>();
        if (count > 0) {
            // 7、分页查询数据
            result = mongoTemplate.find(queryCriteria, Property.class);
            log.info("query总时间为: " + (System.currentTimeMillis() - startTime));
        }
        return PageableExecutionUtils.getPage(result, pageable, () -> count);
    }

    @Override
    public Page<Property> findAllHotSaleByParams(SalePropertyQueryDto queryDto, Pageable pageable) {
        // 1、拼查询公共条件
        Criteria commonCriteria = createFindQuery(queryDto);

        // 2、拼每个查询特有的一些查询条件
        Criteria saleCritera = createSaleQuery(queryDto);
        Query queryCriteria = new Query();
        queryCriteria.addCriteria(new Criteria().andOperator(commonCriteria, saleCritera));

        // 3、拼分页参数
        queryCriteria.with(pageable);

        // 4、拼排序参数
        queryCriteria.with(Sort.by(Sort.Order.asc("recommendSort")));

        // 5、指定字段
        createSaleFields(queryCriteria);

        // 6、查询记录条件
        long count = mongoTemplate.count(queryCriteria, Property.class);

        List<Property> result = new ArrayList<>();
        if (count > 0) {
            // 7、分页查询数据
            result = mongoTemplate.find(queryCriteria, Property.class);
        }

        return PageableExecutionUtils.getPage(result, pageable, () -> count);
    }

    @Override
    public List<Property> findAllSaleByParams(SalePropertyQueryDto queryDto) {
        // 1、拼查询公共条件
        Criteria commonCriteria = createFindQuery(queryDto);

        // 2、在 queryCriteria基础上再拼每个查询特有的一些查询条件
        Criteria saleCritera = createSaleQuery(queryDto);
        Query queryCriteria = new Query();
        queryCriteria.addCriteria(new Criteria().andOperator(commonCriteria, saleCritera));

        // 3、指定字段
        createSaleFields(queryCriteria);
        List<Property> propertyList = mongoTemplate.find(queryCriteria, Property.class);
        //图片水印处理
        //PropertyWaterMark propertyWaterMark = getPropertyWaterMark();
        //for (Property property : propertyList) {
        //    property.setMainImageUrl(commonService.propertyWaterMark(property.getMainImageUrl(), propertyWaterMark));
        //}
        return propertyList;
    }

    @Override
    public Page<Property> findAllRentByParams(RentPropertyQueryDto queryDto, Pageable pageable) {
        handleQueryDto(queryDto);

        // 1、拼查询公共条件
        Criteria commonCriteria = createFindQuery(queryDto);

        // 2、在 queryCriteria基础上再拼每个查询特有的一些查询条件
        Criteria rentCriteria = createRentQuery(queryDto);
        Query queryCriteria = new Query();
        queryCriteria.addCriteria(new Criteria().andOperator(commonCriteria, rentCriteria));

        // 3、拼分页参数
        queryCriteria.with(pageable);

        // 4、拼排序参数
        createFindSort(queryCriteria, queryDto.getSort());

        // 5、指定字段
        createRentFields(queryCriteria);

        // 6、查询记录条件
        long count = mongoTemplate.count(queryCriteria, Property.class);
        List<Property> result = new ArrayList<>();
        if (count > 0) {
            // 7、分页查询数据
            result = mongoTemplate.find(queryCriteria, Property.class);
            //房源图片水印处理,此处为二手房列表页,只处理封面图
        }
        return PageableExecutionUtils.getPage(result, pageable, () -> count);
    }

    @Override
    public Page<Property> findSameRentByParams(String propertyUniqueUuid, RentPropertyQueryDto queryDto, Pageable pageable) {

        handleQueryDto(queryDto);

        // 1、拼查询公共条件
        Criteria commonCriteria = createFindQuery(queryDto);

        // 2、在 queryCriteria基础上再拼每个查询特有的一些查询条件
        Criteria rentCriteria = createRentQuery(queryDto);

        //过滤自身
        rentCriteria.and("propertyUniqueUuid").ne(propertyUniqueUuid);

        Query queryCriteria = new Query();
        queryCriteria.addCriteria(new Criteria().andOperator(commonCriteria, rentCriteria));

        // 3、拼分页参数
        queryCriteria.with(pageable);

        // 4、拼排序参数
        createFindSort(queryCriteria, queryDto.getSort());

        // 5、指定字段
        createRentFields(queryCriteria);

        // 6、查询记录条件
        long count = mongoTemplate.count(queryCriteria, Property.class);
        List<Property> result = new ArrayList<>();
        if (count > 0) {
            // 7、分页查询数据
            result = mongoTemplate.find(queryCriteria, Property.class);
        }
        return PageableExecutionUtils.getPage(result, pageable, () -> count);
    }

    @Override
    public Page<Property> findAllHotRentByParams(RentPropertyQueryDto queryDto, Pageable pageable) {
        // 1、拼查询公共条件
        Criteria commonCriteria = createFindQuery(queryDto);

        // 2、在 queryCriteria基础上再拼每个查询特有的一些查询条件
        Criteria rentCriteria = createRentQuery(queryDto);
        Query queryCriteria = new Query();
        queryCriteria.addCriteria(new Criteria().andOperator(commonCriteria, rentCriteria));

        // 3、拼分页参数
        queryCriteria.with(pageable);

        // 4、拼排序参数
        queryCriteria.with(Sort.by(Sort.Order.asc("recommendSort")));

        // 5、指定字段
        createRentFields(queryCriteria);

        // 6、查询记录条件
        long count = mongoTemplate.count(queryCriteria, Property.class);
        List<Property> result = new ArrayList<>();
        if (count > 0) {
            // 7、分页查询数据
            result = mongoTemplate.find(queryCriteria, Property.class);
        }
        return PageableExecutionUtils.getPage(result, pageable, () -> count);
    }

    @Override
    public List<Property> findAllRentByParams(RentPropertyQueryDto queryDto) {
        // 1、拼查询公共条件
        Criteria commonCriteria = createFindQuery(queryDto);

        // 2、在 queryCriteria基础上再拼每个查询特有的一些查询条件
        Criteria rentCriteria = createRentQuery(queryDto);
        Query queryCriteria = new Query();
        queryCriteria.addCriteria(new Criteria().andOperator(commonCriteria, rentCriteria));

        // 3、指定字段
        createRentFields(queryCriteria);
        List<Property> propertyList = mongoTemplate.find(queryCriteria, Property.class);
        //图片水印处理
        //PropertyWaterMark propertyWaterMark = getPropertyWaterMark();
        //for (Property property : propertyList) {
        //    property.setMainImageUrl(commonService.propertyWaterMark(property.getMainImageUrl(), propertyWaterMark));
        //}
        return propertyList;
    }

    @Override
    public void updateProperty(Property property) {
        Query query = new Query(Criteria.where("id").is(property.getId()));

        Update update = new Update();
        update.set("recommend", property.getRecommend());
        update.set("upDownFlag", property.getUpDownFlag());
        update.set("updateTime", new Date());
        mongoTemplate.update(Property.class)
                .matching(query)
                .apply(update)
                .withOptions(FindAndModifyOptions.options().returnNew(true))
                .findAndModifyValue();
    }

    @Override
    public List<EstateGroupListDto> getEstatePropertyNum() {
        //上架房源统计
        Criteria criteria = Criteria.where("upDownFlag").is(UpDownFlagConstants.UP_FLAG.getValue());
        //0615 加上房源状态为“有效”
        criteria.and("tradeStatus").is("有效");
        //房源筛选条件
        criteria.and("square").ne(null);
        Criteria c1 = new Criteria();
        c1.orOperator(Criteria.where("tradeType").is(PropertyTradeTypeConstants.SALE), Criteria.where("tradeType").is(PropertyTradeTypeConstants.ALL));
        Criteria c2 = new Criteria();
        c2.orOperator(Criteria.where("tradeType").is(PropertyTradeTypeConstants.RENT), Criteria.where("tradeType").is(PropertyTradeTypeConstants.ALL));
        criteria.orOperator(
                c1.and("sellPrice").ne(null).and("sellUnitPrice").ne(null),
                c2.and("rentPrice").ne(null)/*.and("rentUnitPrice").ne(null)*/
        );
        Aggregation aggregationSale = Aggregation.newAggregation(Aggregation.match(criteria),
                Aggregation.group("estateUniqueUuid", "tradeType")
                        .first("estateUniqueUuid").as("estateUniqueUuid")
                        .first("tradeType").as("tradeType")
                        .count().as("total"));
        AggregationResults<EstateGroupListDto> property = mongoTemplate.aggregate(aggregationSale, "property_property", EstateGroupListDto.class);
        return property.getMappedResults();
    }

    @Override
    public List<EstateGroupListDto> getRockEstatePropertyNum(Long estateRockId, String corporationCode, String cityCode) {
        //上架房源统计
        Criteria criteria = Criteria.where("estateRockId").is(estateRockId)
                .and("corporationCode").is(corporationCode)
                .and("cityCode").is(cityCode)
                .and("upDownFlag").is(UpDownFlagConstants.UP_FLAG.getValue())
                .and("square").ne(null);
        Criteria c1 = new Criteria();
        c1.orOperator(Criteria.where("tradeType").is(PropertyTradeTypeConstants.SALE), Criteria.where("tradeType").is(PropertyTradeTypeConstants.ALL));
        Criteria c2 = new Criteria();
        c2.orOperator(Criteria.where("tradeType").is(PropertyTradeTypeConstants.RENT), Criteria.where("tradeType").is(PropertyTradeTypeConstants.ALL));
        criteria.orOperator(
                c1.and("sellPrice").ne(null).and("sellUnitPrice").ne(null),
                c2.and("rentPrice").ne(null)/*.and("rentUnitPrice").ne(null)*/
        );
        Aggregation aggregationSale = Aggregation.newAggregation(Aggregation.match(criteria),
                Aggregation.group("tradeType")
                        .first("tradeType").as("tradeType")
                        .count().as("total"));
        AggregationResults<EstateGroupListDto> property = mongoTemplate.aggregate(aggregationSale, "property_property", EstateGroupListDto.class);
        return property.getMappedResults();
    }

    @Override
    public long batchDownProperty(PropertyRules propertyRules, String corporationCode, long currentTimeMillis) {
        if (!propertyRules.isValidParam()) {
            return 0;
        }
        Criteria criteria = createCriteria(currentTimeMillis);
        criteria.and("corporationCode").is(corporationCode);

        Criteria criteria1 = new Criteria();
        List<Criteria> list = new LinkedList<>();
        if (propertyRules.isHousePhoto() && propertyRules.getHousePhotoNum() != null && propertyRules.getHousePhotoNum() >= 0) {
            list.add(Criteria.where("photoList." + propertyRules.getHousePhotoNum()).exists(false));
        }
        if (propertyRules.isHouseTypePhoto()) {
            list.add(Criteria.where("photoList").not().elemMatch(Criteria.where("photoCategory").is("fangxing")));
        }
        if (propertyRules.isPropertyVr()) {
            list.add(Criteria.where("existVr").ne(true));
        }
        if (propertyRules.isPropertyVideo()) {
            list.add(Criteria.where("videoUrl").exists(false));
        }
        if (propertyRules.isCompleteYear()) {
            list.add(Criteria.where("completeYear").exists(false));
        }
        if (propertyRules.isTitle()) {
//            criteria.and("propertyExplainList").not().elemMatch(Criteria.where("title").ne(""));
            list.add(Criteria.where("propertyExplainList").not().elemMatch(Criteria.where("title").ne("")));
            //criteria.and("propertyExplainList.0").exists(false);
        }
        if (propertyRules.isContent()) {
//            criteria.and("propertyExplainList").not().elemMatch(Criteria.where("content").ne(""));
            list.add(Criteria.where("propertyExplainList").not().elemMatch(Criteria.where("content").ne("")));
        }

        if (list.size() > 1) {
            criteria1.orOperator(list.toArray(new Criteria[list.size()]));
        } else {
            criteria1 = list.get(0);
        }

        Query query = new Query();
        query.addCriteria(new Criteria().andOperator(criteria, criteria1));

        Update update = new Update();
        update.set("upDownFlag", UpDownFlagConstants.DOWN_FLAG.getValue());
        update.set("rulesHandle", true);
        UpdateResult updateResult = mongoTemplate.updateMulti(query, update, Property.class);
        return updateResult.getModifiedCount();
    }


    @Override
    public long batchDownV20Property(PropertyRules propertyRules, String corporationCode, long currentTimeMillis) {
        Criteria criteria = createCriteria(currentTimeMillis);
        criteria.and("corporationCode").is(corporationCode);

        Criteria criteria1 = new Criteria();
        List<Criteria> list = new LinkedList<>();
        if (propertyRules.isHousePhoto() && propertyRules.getHousePhotoNum() != null && propertyRules.getHousePhotoNum() >= 0) {
            list.add(Criteria.where("photoList." + propertyRules.getHousePhotoNum()).exists(false));
        }
        if (propertyRules.isHouseTypePhoto()) {
            list.add(Criteria.where("photoList").not().elemMatch(Criteria.where("photoCategory").is("fangxing")));
        }
        if (propertyRules.isPropertyVr()) {
            list.add(Criteria.where("existVr").ne(true));
        }
        if (propertyRules.isPropertyVideo()) {
            list.add(Criteria.where("videoUrl").exists(false));
        }
        if (propertyRules.isCompleteYear()) {
            list.add(Criteria.where("completeYear").exists(false));
        }
        if (propertyRules.isTitle()) {
            list.add(Criteria.where("title").exists(false));
        }
        if (propertyRules.isContent()) {
            list.add(Criteria.where("propertyExplain").exists(false));
        }
        if (propertyRules.isVerifyCode()){
            list.add(Criteria.where("verifyCode").exists(false));
        }
        if (propertyRules.isVerifyQrCode()){
            list.add(Criteria.where("verifyQrCode").exists(false));
        }
        if (propertyRules.isConsignCode()){
            list.add(Criteria.where("consignCode").exists(false));
        }
        if (propertyRules.isPrivy() && !CollectionUtils.isEmpty(propertyRules.getPrivyList())){
            list.add(Criteria.where("privy").nin(propertyRules.getPrivyList()));
        }
        if (propertyRules.isProtectStatus()){
            list.add(Criteria.where("protectedFlag").ne(true));
        }

        if (CollectionUtils.isEmpty(list)){
            return 0;
        }else if (list.size() > 1) {
            criteria1.orOperator(list.toArray(new Criteria[list.size()]));
        } else {
            criteria1 = list.get(0);
        }

        Query query = new Query();
        query.addCriteria(new Criteria().andOperator(criteria, criteria1));

        Update update = new Update();
        update.set("upDownFlag", UpDownFlagConstants.DOWN_FLAG.getValue());
        update.set("rulesHandle", true);
        UpdateResult updateResult = mongoTemplate.updateMulti(query, update, Property.class);
        return updateResult.getModifiedCount();
    }

    @Override
    public long batchUpV20Property(String corporationCode, long currentTimeMillis) {
        Criteria criteria = createCriteria(currentTimeMillis);
        criteria.and("corporationCode").is(corporationCode);
        Update update = new Update();
        update.set("upDownFlag", UpDownFlagConstants.UP_FLAG.getValue());
        update.set("rulesHandle", true);
        UpdateResult updateResult = mongoTemplate.updateMulti(new Query().addCriteria(criteria), update, Property.class);
        return updateResult.getModifiedCount();
    }


    @Override
    public List<String> getUndisposedUuidList(String companyUuid, long currentTimeMillis) {
        Criteria criteria = createCriteria(currentTimeMillis);
        criteria.and("companyUuid").is(companyUuid);
        TypedAggregation<Property> tagg = TypedAggregation.newAggregation(Property.class, Arrays.asList(
                TypedAggregation.match(criteria),
                TypedAggregation.group("propertyUuid").first("propertyUuid").as("propertyUuid"),
                TypedAggregation.project("propertyUuid")
        ));
        AggregationResults result = mongoTemplate.aggregate(tagg, Property.class);
        List<Property> resultList = result.getMappedResults();
        List<String> uuidList = Optional.ofNullable(resultList).orElseGet(Lists::newArrayList).stream().map(Property::getPropertyUuid).collect(Collectors.toList());
        return uuidList;
    }

    @Override
    public long batchProcessingByUuidList(List<String> uuidList, String companyUuid, String upDownFlag) {
        if (CollectionUtils.isEmpty(uuidList)) {
            return 0;
        }
        Criteria criteria = new Criteria();
        criteria.and("companyUuid").is(companyUuid);
        criteria.and("propertyUuid").in(uuidList);
        Update update = new Update();
        update.set("upDownFlag", upDownFlag);
        update.set("rulesHandle", true);
        UpdateResult updateResult = mongoTemplate.updateMulti(new Query().addCriteria(criteria), update, Property.class);
        return updateResult.getModifiedCount();
    }

    private Criteria createCriteria(long currentTimeMillis) {
        Criteria criteria = new Criteria();
        criteria.and("rulesHandle").is(false);
        criteria.and("updateTime").lte(new Timestamp(currentTimeMillis));
        //匹配没有手动上架 或 手动上架时间在7天前
        criteria.orOperator(Criteria.where("manualUpTime").exists(false), Criteria.where("manualUpTime").is(null), Criteria.where("manualUpTime").lt(new Timestamp(currentTimeMillis - (7 * DateUtil.DAY_MILLISECONDS))));
        return criteria;
    }

    @Override
    public List<Property> findAllPropertyByTradeStatus(String tradeStatus, List<String> propertyUuids) {

        String corporationCode = QfContextHolder.getContext().getCorporationCode();
        //已租或已售   tradeStatus
        if (tradeStatus.equals(MyHouseStatusConstants.RENTED.getTradeStatus())
                || tradeStatus.equals(MyHouseStatusConstants.SOLD.getTradeStatus())) {
            return propertyRepository.findAllByCorporationCodeAndTradeStatusAndPropertyUuidIn(corporationCode, tradeStatus, propertyUuids);
        }
        //在租 在售
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and("corporationCode").is(corporationCode);
        criteria.orOperator(Criteria.where("tradeType").is(MyHouseStatusConstants.getTradeTypeByParam(tradeStatus)), Criteria.where("tradeType").is(PropertyTradeTypeConstants.ALL));
        criteria.and("tradeStatus").is(MyHouseStatusConstants.IN_STOCK.getTradeStatus());
        criteria.and("propertyUuid").in(propertyUuids);
        query.addCriteria(criteria);
        return mongoTemplate.find(query, Property.class);
    }

    @Override
    public List<Property> findAllRentProperty(String tradeStatus, List<String> propertyUuids) {
        String corporationCode = QfContextHolder.getContext().getCorporationCode();
        //分类 出租  已租
        if (StringUtils.isNotBlank(tradeStatus)) {
            Query query = new Query();
            Criteria criteria = new Criteria();
            criteria.and("corporationCode").is(corporationCode);
            //出租  租售
            if (tradeStatus.equals(MyHouseStatusConstants.ON_RENT.getTradeType())) {
                criteria.orOperator(Criteria.where("tradeType").is(MyHouseStatusConstants.getTradeTypeByParam(tradeStatus))
                        , Criteria.where("tradeType").is(PropertyTradeTypeConstants.ALL));
                criteria.and("tradeStatus").is(MyHouseStatusConstants.IN_STOCK.getTradeStatus());
            } else {
                criteria.and("tradeStatus").is(MyHouseStatusConstants.RENTED.getTradeStatus());
            }
            criteria.and("propertyUuid").in(propertyUuids);
            query.addCriteria(criteria);
            List<Property> propertyList = mongoTemplate.find(query, Property.class);
            return propertyList;
        }
        //全部
        Query queryAll = new Query();
        Criteria criteriaAll = new Criteria();
        criteriaAll.and("corporationCode").is(corporationCode);
        criteriaAll.and("tradeType").in(Lists.newArrayList(MyHouseStatusConstants.ON_RENT.getTradeType(), PropertyTradeTypeConstants.ALL));
        criteriaAll.and("tradeStatus").in(Lists.newArrayList(MyHouseStatusConstants.IN_STOCK.getTradeStatus(), MyHouseStatusConstants.RENTED.getTradeStatus()));
        criteriaAll.and("propertyUuid").in(propertyUuids);
        queryAll.addCriteria(criteriaAll);

        List<Property> propertyList = Optional.ofNullable(mongoTemplate.find(queryAll, Property.class)).orElseGet(Lists::newArrayList)
                .stream().map(property -> {
                    if (StringUtils.equals(property.getTradeStatus(), MyHouseStatusConstants.RENTED.getParam())) {
                        property.setTradeType(property.getTradeStatus());
                    }
                    return property;
                }).collect(Collectors.toList());

        return propertyList;
    }

    @Override
    public List<Property> findAllSaleProperty(String tradeStatus, List<String> propertyUuids) {
        String corporationCode = QfContextHolder.getContext().getCorporationCode();
        //分类
        if (StringUtils.isNotBlank(tradeStatus)) {
            Query query = new Query();
            Criteria criteria = new Criteria();
            criteria.and("corporationCode").is(corporationCode);
            //出售 已售
            if (tradeStatus.equals(MyHouseStatusConstants.IN_STOCK.getTradeType())) {
                criteria.orOperator(Criteria.where("tradeType").is(MyHouseStatusConstants.getTradeTypeByParam(tradeStatus))
                        , Criteria.where("tradeType").is(PropertyTradeTypeConstants.ALL));
                criteria.and("tradeStatus").is(MyHouseStatusConstants.IN_STOCK.getTradeStatus());
            } else {
                criteria.and("tradeStatus").is(MyHouseStatusConstants.SOLD.getTradeStatus());
            }
            criteria.and("propertyUuid").in(propertyUuids);
            query.addCriteria(criteria);
            List<Property> propertyList = mongoTemplate.find(query, Property.class);
            return propertyList;
        }
        //全部
        Query queryAll = new Query();
        Criteria criteriaAll = new Criteria();
        criteriaAll.and("corporationCode").is(corporationCode);
        criteriaAll.and("tradeType").in(Lists.newArrayList(MyHouseStatusConstants.IN_STOCK.getTradeType(), PropertyTradeTypeConstants.ALL));
        criteriaAll.and("tradeStatus").in(Lists.newArrayList(MyHouseStatusConstants.IN_STOCK.getTradeStatus(), MyHouseStatusConstants.SOLD.getTradeStatus()));
        criteriaAll.and("propertyUuid").in(propertyUuids);
        queryAll.addCriteria(criteriaAll);

        List<Property> propertyList = Optional.ofNullable(mongoTemplate.find(queryAll, Property.class)).orElseGet(Lists::newArrayList)
                .stream().map(property -> {
                    if (StringUtils.equals(property.getTradeStatus(), MyHouseStatusConstants.SOLD.getParam())) {
                        property.setTradeType(property.getTradeStatus());
                    }
                    return property;
                }).collect(Collectors.toList());

        return propertyList;
    }

    @Override
    public List<Property> findAllMySaleHouseByParams(SalePropertyQueryDto queryDto) {
        // TODO: 2020/12/7
        QfContext qfContext = QfContextHolder.getContext();
        Criteria commonCriteria = Criteria.where("corporationCode").is(StringUtils.defaultString(queryDto.getCorporationCode(), qfContext.getCorporationCode()));
        commonCriteria.and("propertyUuid").in(queryDto.getPropertyUuids());
        commonCriteria.and("tradeType").in(Lists.newArrayList(MyHouseStatusConstants.IN_STOCK.getTradeType(), PropertyTradeTypeConstants.ALL));
        commonCriteria.and("tradeStatus").in(Lists.newArrayList(MyHouseStatusConstants.IN_STOCK.getTradeStatus(), MyHouseStatusConstants.SOLD.getTradeStatus()));
        //在 queryCriteria基础上再拼每个查询特有的一些查询条件
        //Criteria saleCritera = createSaleQuery(queryDto);
        Query queryCriteria = new Query();
        queryCriteria.addCriteria(commonCriteria);
        // 指定字段
        createSaleFields(queryCriteria);
        return mongoTemplate.find(queryCriteria, Property.class);
    }

    @Override
    public List<Property> findAllMyRentHouseByParams(RentPropertyQueryDto queryDto) {
        QfContext qfContext = QfContextHolder.getContext();
        Criteria commonCriteria = Criteria.where("corporationCode").is(StringUtils.defaultString(queryDto.getCorporationCode(), qfContext.getCorporationCode()));
        commonCriteria.and("propertyUuid").in(queryDto.getPropertyUuids());
        commonCriteria.and("tradeType").in(Lists.newArrayList(MyHouseStatusConstants.ON_RENT.getTradeType(), PropertyTradeTypeConstants.ALL));
        commonCriteria.and("tradeStatus").in(Lists.newArrayList(MyHouseStatusConstants.IN_STOCK.getTradeStatus(), MyHouseStatusConstants.RENTED.getTradeStatus()));
        //在 queryCriteria基础上再拼每个查询特有的一些查询条件
        //Criteria saleCritera = createSaleQuery(queryDto);
        Query queryCriteria = new Query();
        queryCriteria.addCriteria(commonCriteria);
        // 指定字段
        createSaleFields(queryCriteria);
        return mongoTemplate.find(queryCriteria, Property.class);
    }

    @Override
    public List<NewPropertySimpleDto> getNewHouseSimpleList(NewPropertyQueryDto queryDto) {
        List<NewPropertySimpleDto> list = new LinkedList<>();
        List<EmployeeProperty> employeeProperties = employeePropertyRepository.findByEmployeeUniqueUuid(queryDto.getEmployeeUniqueUuid());
        List<String> firstNinList = new LinkedList<>();
        List<String> saleNinList = new LinkedList<>();
        List<String> rentNinList = new LinkedList<>();
        for (EmployeeProperty employeeProperty : employeeProperties) {
            switch (employeeProperty.getPropertyType()) {
                case "新房":
                    firstNinList.add(employeeProperty.getPropertyUniqueUuid());
                    break;
                case "二手房":
                    saleNinList.add(employeeProperty.getPropertyUniqueUuid());
                    break;
                case "租房":
                    rentNinList.add(employeeProperty.getPropertyUniqueUuid());
                    break;
            }
        }
        FirsthandEstateQueryDto firsthandEstateQueryDto = new FirsthandEstateQueryDto();
        firsthandEstateQueryDto.setCityCode(queryDto.getCityCode());
        firsthandEstateQueryDto.setUpDownFlag(UpDownFlagConstants.UP_FLAG.getValue());
        firsthandEstateQueryDto.setNewStatus(Boolean.TRUE);
        firsthandEstateQueryDto.setNotEstateUniqueUuids(firstNinList.size() > 0 ? firstNinList : null);
        List<FirsthandEstate> firsthandEstateList = firsthandEstateService.findAllByParams(firsthandEstateQueryDto, PageRequest.of(0, 4)).getContent();

        SalePropertyQueryDto salePropertyQueryDto = new SalePropertyQueryDto();
        salePropertyQueryDto.setCityCode(queryDto.getCityCode());
        salePropertyQueryDto.setUpDownFlag(UpDownFlagConstants.UP_FLAG.getValue());
        salePropertyQueryDto.setNewStatus(Boolean.TRUE);
        salePropertyQueryDto.setNotPropertyUniqueUuids(saleNinList.size() > 0 ? saleNinList : null);
        List<Property> salePropertyList = findAllSaleByParams(salePropertyQueryDto, PageRequest.of(0, 4)).getContent();

        RentPropertyQueryDto rentPropertyQueryDto = new RentPropertyQueryDto();
        rentPropertyQueryDto.setCityCode(queryDto.getCityCode());
        rentPropertyQueryDto.setUpDownFlag(UpDownFlagConstants.UP_FLAG.getValue());
        rentPropertyQueryDto.setNewStatus(Boolean.TRUE);
        rentPropertyQueryDto.setNotPropertyUniqueUuids(rentNinList.size() > 0 ? rentNinList : null);
        List<Property> rentPropertyList = findAllRentByParams(rentPropertyQueryDto, PageRequest.of(0, 4)).getContent();

        if (!CollectionUtils.isEmpty(firsthandEstateList)) {
            for (FirsthandEstate firsthandEstate : firsthandEstateList) {
                StringBuilder sb = new StringBuilder(firsthandEstate.getEstateName());
                if (StringUtils.isNotEmpty(firsthandEstate.getBuildingAreaRange())){
                    sb.append(" " + firsthandEstate.getBuildingAreaRange()+ "㎡");
                }
                if (!CollectionUtils.isEmpty(firsthandEstate.getHouseTypeList())){
                    sb.append(" " + firsthandEstate.getHouseTypeList().size() + "个户型");
                }
                if (firsthandEstate.getAveragePrice() != null){
                    sb.append(" 均价" + firsthandEstate.getAveragePrice() + "元");
                }
                list.add(NewPropertySimpleDto.builder()
                        .uniqueUuid(firsthandEstate.getEstateUniqueUuid())
                        .businessType(BusinessConstants.FIRSTHAND_ESTATE.getCode())
                        .createdTime(firsthandEstate.getCreatedTime())
                        .showInfo(sb.toString())
                        .build());
            }
        }

        if (!CollectionUtils.isEmpty(salePropertyList)) {
            for (Property property : salePropertyList) {
                StringBuilder sb = new StringBuilder(property.getEstateName() + " ");
                sb.append(property.getCountF() == null ? "0" : property.getCountF()).append("室")
                        .append((property.getCountT() == null ? "0" : property.getCountT()) + "厅")
                        .append((property.getCountW() == null ? "0" : property.getCountW()) + "卫")
                        .append(" " + property.getSquare()+ "㎡")
                        .append(" " + property.getSellPrice()+ "万元")
                        .append(" 单价" + property.getSellUnitPrice()+ "元");

                list.add(NewPropertySimpleDto.builder()
                        .uniqueUuid(property.getPropertyUniqueUuid())
                        .businessType(BusinessConstants.SALE_PROPERTY.getCode())
                        .createdTime(property.getCreatedTime())
                        .showInfo(sb.toString())
                        .build());
            }
        }

        if (!CollectionUtils.isEmpty(rentPropertyList)) {
            for (Property property : rentPropertyList) {
                StringBuilder sb = new StringBuilder(property.getEstateName() + " ");
                sb.append(property.getCountF() == null ? "0" : property.getCountF()).append("室")
                        .append((property.getCountT() == null ? "0" : property.getCountT()) + "厅")
                        .append((property.getCountW() == null ? "0" : property.getCountW()) + "卫")
                        .append(" " + property.getSquare()+ "㎡")
                        .append(" " + property.getRentPrice()+ "元/月");

                list.add(NewPropertySimpleDto.builder()
                        .uniqueUuid(property.getPropertyUniqueUuid())
                        .businessType(BusinessConstants.RENT_PROPERTY.getCode())
                        .createdTime(property.getCreatedTime())
                        .showInfo(sb.toString())
                        .build());
            }
        }

        Collections.sort(list, new Comparator<NewPropertySimpleDto>() {
            @Override
            public int compare(NewPropertySimpleDto o1, NewPropertySimpleDto o2) {
                int i = (int) (o2.getCreatedTime().getTime() - o1.getCreatedTime().getTime());
                return i;
            }
        });

        return list.size() > 4 ? list.subList(0, 4) : list;
    }

    @Override
    public List<PropertyImageDto> dealPropertyImgWaterMark(List<PropertyImageDto> propertyImageDtos, String propertyUniqueUuid, String companyUuid) {

        CityCompany cityCompany = cityCompanyRepository.findOneByCompanyUuid(companyUuid);
        if (cityCompany == null) {
            log.info("公司不存在,companyUuid:{}",companyUuid);
            return propertyImageDtos;
        }
        //这里直接判断是否开了水印
        if (cityCompany.getPropertyWaterMark() == null || !StringUtils.equals(cityCompany.getPropertyWaterMark().getWatermark(), WaterMarkConstants.ON)) {
            return propertyImageDtos;
        }

        String companyUuidWaterMarkKey = RedisKeyUtil.getPropertyWaterMarkKey(companyUuid);
        Object obj = redisUtil.hget(companyUuidWaterMarkKey, propertyUniqueUuid);
        if (obj != null) {
            return JSONObject.parseArray(JSONObject.toJSONString(obj), PropertyImageDto.class);
        }
        List<PropertyImageDto> resultList = new ArrayList<>();
        PropertyWaterMark propertyWaterMark = getPropertyWaterMark();
        for (PropertyImageDto imageDto : propertyImageDtos) {
            if (StringUtils.equals(PropertyImageConstants.VR_TYPE.getValue(), imageDto.getImageType())) {
                String imgUrl = imageDto.getImgUrl();
                if (imgUrl.contains("?")){
                    imgUrl = imgUrl.substring(0, imgUrl.indexOf("?"));
                }
                imageDto.setImgUrl(commonService.propertyWaterMark(imgUrl, propertyWaterMark));
            } else {
                imageDto.setImgUrl(commonService.propertyWaterMark(imageDto.getImgUrl(), propertyWaterMark));
            }
            resultList.add(imageDto);
        }
        redisUtil.hset(companyUuidWaterMarkKey, propertyUniqueUuid, resultList);
        return resultList;
    }

    /**
     * 获取公司水印设置
     * @return
     */
    private PropertyWaterMark getPropertyWaterMark() {
        QfContext context = QfContextHolder.getContext();
        List<CityCompany> cityCompanyList = cityCompanyRepository.findAllByCorporationCodeAndCityCodeAndMainCityFlag(context.getCorporationCode(), context.getCityCode(), 1);
        if (CollectionUtils.isEmpty(cityCompanyList)) {
            return null;
        }
        return cityCompanyList.get(0).getPropertyWaterMark();
    }

    @Override
    public List<MainSearchDetailDTO> eatateListSearchByName(MainSearchQueryDTO mainSearchQueryDTO) {

        QfContext context = QfContextHolder.getContext();

        Criteria criteria = Criteria.where("corporationCode").is(context.getCorporationCode())
                .and("cityCode").is(mainSearchQueryDTO.getCityCode())
                .and("upDownFlag").is(UpDownFlagConstants.UP_FLAG.getValue())
                .and("estateName").regex(".*?" + mainSearchQueryDTO.getSearchName() + ".*")
                .and("square").ne(null);

        //这里加上出租、出售的筛选条件
        if (SearchTypeConstants.SALE_PROPERTY.getValue().equals(mainSearchQueryDTO.getSearchType())) {
            criteria.orOperator(Criteria.where("tradeType").is(PropertyTradeTypeConstants.SALE), Criteria.where("tradeType").is(PropertyTradeTypeConstants.ALL));
            criteria.and("sellPrice").ne(null);
            criteria.and("sellUnitPrice").ne(null);
        } else if (SearchTypeConstants.RENT_PROPERTY.getValue().equals(mainSearchQueryDTO.getSearchType())){
            criteria.orOperator(Criteria.where("tradeType").is(PropertyTradeTypeConstants.RENT), Criteria.where("tradeType").is(PropertyTradeTypeConstants.ALL));
            criteria.and("rentPrice").ne(null);
//            criteria.and("rentUnitPrice").ne(null);
        }

        Aggregation agg = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.group("estateUniqueUuid")
                        .first("estateUniqueUuid").as("estateUniqueUuid")
                        .first("estateName").as("estateName")
                        .first("areaName").as("areaName")
                        .first("estateRockId").as("estateRockId")
                        .count().as("count"),
                Aggregation.sort(DESC, "count") //分组后排序
        );

        AggregationResults<EstateListAggregationDto> aggregate = mongoTemplate.aggregate(agg, "property_property", EstateListAggregationDto.class);
        List<EstateListAggregationDto> mappedResults = aggregate.getMappedResults();
        List<MainSearchDetailDTO> resultList = new ArrayList<>();

        if (!CollectionUtils.isEmpty(mappedResults)) {
            resultList = mappedResults.stream().filter(f -> Objects.nonNull(f.getEstateRockId())).map(estateDto -> {
                MainSearchDetailDTO mainSearchDetailDTO = new MainSearchDetailDTO();
                mainSearchDetailDTO.setEstateUniqueUuid(estateDto.getEstateUniqueUuid());
                mainSearchDetailDTO.setEstateName(estateDto.getEstateName());
                mainSearchDetailDTO.setAreaName(estateDto.getAreaName());
                mainSearchDetailDTO.setEstateRockId(estateDto.getEstateRockId());
                if (SearchTypeConstants.SALE_PROPERTY.getValue().equals(mainSearchQueryDTO.getSearchType())) {
                    mainSearchDetailDTO.setSaleNum(estateDto.getCount() == null ? 0 : estateDto.getCount());
                } else if (SearchTypeConstants.RENT_PROPERTY.getValue().equals(mainSearchQueryDTO.getSearchType())) {
                    mainSearchDetailDTO.setRentNum(estateDto.getCount() == null ? 0 : estateDto.getCount());
                } else {
                    mainSearchDetailDTO.setSaleNum(estateDto.getCount() == null ? 0 : estateDto.getCount());
                    mainSearchDetailDTO.setRentNum(estateDto.getCount() == null ? 0 : estateDto.getCount());
                }
                return mainSearchDetailDTO;
            }).collect(Collectors.toList());
        }
        return resultList;
    }
}
